<?php

namespace app\admin\model\booking;

use think\Model;
use think\Log;
use addons\epay\library\Service;
use Yansongda\Pay\Pay;
use addons\booking\model\OrderCalendar;

class Order extends Model
{

    // 表名
    protected $name = 'booking_order';

    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';

    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    protected $deleteTime = false;

    // 追加属性
    protected $append = [
        'type_text',
        'paytime_text',
        'checkin_time_text',
        'leave_time_text',
        'status_text'
    ];


    public function getTypeList()
    {
        return ['0' => __('Type 0'), '1' => __('Type 1'), '2' => __('Type 2')];
    }

    public function getStatusList()
    {
        return [
            'created'     => __('Status created'),
            'paid'        => __('Status paid'),
            'checkined'   => __('Status checkined'),
            'expired'     => __('Status expired'),
            'canceled'    => __('Status canceled'),
            'refunding'   => __('Status refunding'),
            'checkouting' => __('Status checkouting'),
            'evaluate'    => __('Status evaluate'),
            'toshopay'    => __('Status toshopay'),
            'finished'    => __('Status finished'),
        ];
    }


    public function getStatusGoods()
    {
        return [
            'created'   => __('Status created'),
            'paid'      => __('Status paid'),
            'shipped'   => __('Status shipped'),
            'expired'   => __('Status expired'),
            'canceled'  => __('Status canceled'),
            'refunding' => __('Status refunding'),
            'evaluate'  => __('Status evaluate'),
            'finished'  => __('Status finished'),
        ];
    }


    public function getTypeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['type']) ? $data['type'] : '');
        $list = $this->getTypeList();
        return isset($list[$value]) ? $list[$value] : '';
    }


    public function getPaytimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['paytime']) ? $data['paytime'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getCheckinTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['checkin_time']) ? $data['checkin_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getLeaveTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['leave_time']) ? $data['leave_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }

    public function getActualCheckinTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['checkin_time']) ? $data['checkin_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getActualCheckoutTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['leave_time']) ? $data['leave_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
        $list = $this->getStatusList();
        $list = array_merge($list, $this->getStatusGoods());
        return isset($list[$value]) ? $list[$value] : '';
    }

    protected function setPaytimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    protected function setCheckinTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    protected function setLeaveTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    protected function setActualCheckinTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    protected function setActualCheckoutTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    protected static function init()
    {

        self::afterUpdate(function ($row) {
            $changeData = $row->getChangedData();
            if (isset($changeData['status'])) {
                //取消订单，退款，修改状态，是否售后
                //已预订房间状态修改
                if ($changeData['status'] == 'canceled') {
                    OrderCalendar::editCalendar($row->orderid);
                }
                if ($changeData['status'] == 'refunded') {
                    $config = get_addon_config('booking');
                    OrderCalendar::editCalendar($row->orderid);
                    if ($config['order_refund_sync']) {
                        //执行同步退款
                        \app\admin\model\booking\Order::refund($row->orderid, $row->paytype, $row->payamount);
                    }
                    //已退款，销量恢复
                    if ($row['type'] == 1) {
                        \addons\booking\model\OrderGoods::setGoodsSalesDec($row['orderid']);
                    }
                }
                //退房结束，订单完成，给积分
                if ($changeData['status'] == 'finished') {
                    $config = get_addon_config('booking');
                    if (isset($config['money_score']) && $config['money_score'] > 0) {
                        $money = bcsub($row['payamount'], $row['outamount'], 2);
                        if ($money > 0) {
                            $score = bcmul($money, $config['money_score']);
                            \app\common\model\User::score($score, $row['user_id'], '完成入住订单赠送积分');
                        }
                    }
                }
                if ($row['status'] == 'paid') {
                    if ($row['type'] == 1) {
                        \addons\booking\model\OrderGoods::setGoodsSalesInc($row['orderid']);
                    }
                }
            }
        });
        self::afterInsert(function ($row) {
            //寻找日期范围是否有被预定
            if (OrderCalendar::isHasBooked($row['source_id'], $row['checkin_time'], $row['leave_time'])) {
                throw new \Exception('此时间区域未有房间可预定');
            }
            //房间预订日历记录
            OrderCalendar::addCalendar($row['user_id'], $row['source_id'], $row['orderid'], $row['checkin_time'], $row['leave_time']);
        });
        //订单支付
        self::beforeWrite(function ($row) {
            $changeData = $row->getChangedData();
            if (isset($changeData['status'])) {

                if ($changeData['status'] == 'paid') {
                    $row->method = 'system';
                    $row->paytype = 'system';
                    $row->payamount = $row['amount'];
                    $row->paytime = time();
                }

                if ($changeData['status'] == 'shipped') {
                    $row->delivery_time = time();
                }
            }
        });

        //订单删除
        self::afterDelete(function ($row) {
            OrderCalendar::editCalendar($row->orderid);
        });
    }


    /**
     * 退款
     */
    public static function refund($orderid, $paytype, $payamount)
    {
        if ($payamount <= 0) {
            return true;
        }
        $config = Service::getConfig($paytype);
        try {
            $order = Order::getByOrderid($orderid);
            if ($paytype == 'wechat') {
                $response = Pay::wechat($config)->refund([
                    'type'          => in_array($order['method'], ['miniapp', 'app']) ? $order['method'] : '',
                    'out_trade_no'  => $orderid,
                    'out_refund_no' => time(),
                    'total_fee'     => $payamount * 100,
                    'refund_fee'    => $payamount * 100
                ]);
                if (!$response['result_code'] || $response['result_code'] != 'SUCCESS') {
                    throw new \Exception(($response['err_code'] ?? '') . ':' . ($response['err_code_des'] ?? '未知退款错误'));
                }
            } elseif ($paytype == 'alipay') {
                $response = Pay::alipay($config)->refund([
                    'out_trade_no'  => $orderid,
                    'refund_amount' => $payamount,
                ]);
                if (!$response['code'] || $response['code'] != '10000') {
                    throw new \Exception(($response['code'] ?? '') . ':' . ($response['msg'] ?? '未知退款错误'));
                }
            }
        } catch (\Exception $e) {
            Log::write("[booking][refund][{$orderid}]同步退款失败，失败原因：" . $e->getMessage());
            throw new \Exception("同步退款失败，失败原因：" . $e->getMessage());
        }
        return true;
    }


    /**
     * 资源关联
     *
     * @return void
     */
    public function source()
    {
        $type = $this->getData('type');
        //0=房间，1=商品，2=其他
        switch ($type) {
            case 0:
                return $this->belongsTo('House', 'source_id');
                break;
            case 1:
                return $this->hasMany('OrderGoods', 'orderid', 'orderid');
                break;
        }
    }


    public function User()
    {
        return $this->belongsTo('\app\common\model\User', 'user_id', 'id', [], 'LEFT');
    }

    public function UserCoupon()
    {
        return $this->hasOne('UserCoupon', 'id', 'user_coupon_id', [], 'LEFT');
    }
}
